﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Convertor.Base;
using zijian666.Core.Abstractions;

namespace zijian666.Converts.Core;

/// <summary>
/// 合并多个 <seealso cref="IConvertSettings"/>
/// </summary>
public class MergeConvertSettings : IConvertSettings
{
    /// <summary>
    /// 设置1
    /// </summary>
    private readonly IConvertSettings _settings1;
    /// <summary>
    /// 设置2
    /// </summary>
    private readonly IConvertSettings _settings2;
    /// <summary>
    /// 合并2个设置, 优先使用设置1的
    /// </summary>
    /// <param name="settings1">首选设置</param>
    /// <param name="settings2">次要设置</param>
    public MergeConvertSettings(IConvertSettings settings1, IConvertSettings settings2)
    {
        _settings1 = settings1 ?? throw new ArgumentNullException(nameof(settings1));
        _settings2 = settings2 ?? throw new ArgumentNullException(nameof(settings2));
    }

    /// <summary>
    /// 是否包含某个设置
    /// </summary>
    /// <param name="settings">用于检测是否包含的设置</param>
    /// <returns></returns>
    public virtual bool Contains(IConvertSettings settings) => _settings1 == settings || _settings2 == settings
            || (_settings1 is MergeConvertSettings agg1 && agg1.Contains(settings))
            || (_settings2 is MergeConvertSettings agg2 && agg2.Contains(settings));

    /// <inheritdoc />
    public virtual TraceListener? Trace { get; set; }

    /// <inheritdoc />
    public virtual IConvertor<T>? GetConvertor<T>(IConvertContext context)
    {
        var conv1 = _settings1?.GetConvertor<T>(context);
        var conv2 = _settings2?.GetConvertor<T>(context);
        if (conv1 is null || ReferenceEquals(conv1, conv2))
        {
            return conv2;
        }
        if (conv2 is null)
        {
            return conv1;
        }
        return new AggregateConvertor<T>(conv1, conv2);
    }

    /// <inheritdoc />
    public virtual IEnumerable<ITranslator>? Translators
    {
        get
        {
            if (_settings1.Translators is not null)
            {
                foreach (var item in _settings1.Translators)
                {
                    yield return item;
                }
            }
            else if (_settings2.Translators is not null)
            {
                foreach (var item in _settings2.Translators)
                {
                    yield return item;
                }
            }
        }
    }

    /// <inheritdoc />
    public virtual IStringSerializer? StringSerializer => _settings1?.StringSerializer ?? _settings2?.StringSerializer;

    /// <inheritdoc />
    public virtual CultureInfo? CultureInfo => _settings1?.CultureInfo ?? _settings2?.CultureInfo ?? CultureInfo.CurrentUICulture;

    /// <inheritdoc />
    public virtual NumberFormatInfo? NumberFormatInfo => _settings1?.NumberFormatInfo ?? _settings2?.NumberFormatInfo ?? NumberFormatInfo.CurrentInfo;

    /// <inheritdoc />
    public virtual Encoding? Encoding => _settings1?.Encoding ?? _settings2?.Encoding ?? Encoding.UTF8;

    /// <inheritdoc />
    public virtual StringSeparator? StringSeparator => _settings1?.StringSeparator ?? _settings2?.StringSeparator;

    /// <inheritdoc />
    public virtual StringSplitOptions StringSplitOptions => _settings1.StringSplitOptions & _settings2.StringSplitOptions;

    /// <inheritdoc />
    public virtual IReflectCompiler? ReflectCompiler => _settings1.ReflectCompiler ?? _settings2.ReflectCompiler;

    /// <inheritdoc />
    public virtual bool StrictEnum => _settings1.StrictEnum || _settings2.StrictEnum;

    /// <inheritdoc />
    public override bool Equals(object obj)
    {
        if (obj is MergeConvertSettings agg)
        {
            return _settings1.Equals(agg._settings1) && _settings2.Equals(agg._settings2);
        }
        return false;
    }

    /// <inheritdoc />
    public override int GetHashCode()
    {
        var hashCode = -1215043943;
        hashCode = (hashCode * -1521134295) + EqualityComparer<IConvertSettings>.Default.GetHashCode(_settings1);
        hashCode = (hashCode * -1521134295) + EqualityComparer<IConvertSettings>.Default.GetHashCode(_settings2);
        return hashCode;
    }

    /// <inheritdoc />
    public virtual ToStringArgument? GetToStringArgument(Type type) => _settings1.GetToStringArgument(type) ?? _settings2.GetToStringArgument(type);
}
